package org.esjsoftware.v2m.rim.proxy;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.control.RecordControl;

import org.esjsoftware.v2m.rim.audio.amrtowav.AmrToWav;
import org.esjsoftware.v2m.rim.listener.AudioPlayerListener;

/**
 * 
 * @author Ernest
 *
 */
public class AudioProxy extends Thread {
	AudioRecordObserverInterface _ourObserver;
	private boolean _stopRequest = false;

	private Player recordPlayer;
	private Player player;
	private RecordControl recordControl;
	private ByteArrayOutputStream baos = null;

	private AudioPlayerListener audioPlayerListener;

	public AudioProxy(AudioRecordObserverInterface observer) {
		super();
		this._ourObserver = observer;
	}

	/**
	 * stop is called if the processing should not continue.
	 */
	public void stop() {
		// Tell our observer
		try {
			recordCommit();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		observerError(ObserverInterface.CANCELLED,
				"Voice message recorded.");
		_stopRequest = true; // Will no longer tell Observer anything
		this.interrupt(); // Give our Thread a kick
	}

	private void observerError(int errorCode, String errorMessage) {
		if (!_stopRequest) {
			_ourObserver.processError(errorCode, errorMessage);
		}
	}

	private void observerResponse(ByteArrayOutputStream reply) {
		if (!_stopRequest) {
			_ourObserver.processResponse(reply);
		}
	}

	/**
	 * Process the long running or blocking operation in this Thread Update the
	 * Observer as required using - processStatus, whenever desired and then one
	 * of: - processError, if there was a problem - processResponse, if the data
	 * was obtained OK
	 */
	public void run() {
		long stallTime = 60000; // Will stall for this time -- 60m
		boolean willFail = false; // false - will finshed OK, true - will fail!
		long updateInterval = 1000; // Update Observer every second
		long startTime = System.currentTimeMillis();
		long finishTime = startTime + stallTime;
		long currentTime = startTime;

		if (willFail) {
			// Fail 1/2 way through
			finishTime = startTime + stallTime / 2;
		}

		try {
			record();
		} catch (IOException e1) {
			stop();
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (MediaException e1) {
			stop();
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		while (!_stopRequest && currentTime < finishTime) {
			try {
				Thread.sleep(updateInterval);
			} catch (Exception e) {
			}

			currentTime = System.currentTimeMillis();
		}

		try {
			recordCommit();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			stop();
		}

		// Did we finish OK or badly
		if (willFail) {
			observerError(ObserverInterface.ERROR, "Failed");
		} else {
			observerResponse(baos);
		}

		// Make sure we do nothing else
		_stopRequest = true;
		_ourObserver = null;

	}

	public void stopAudioPlayer() {
		player.close();
		fireEvent();
	}
	
	public void record() throws IOException, MediaException {
		recordPlayer = Manager.createPlayer("capture://audio?encoding=pcm");
		recordPlayer.realize();
		recordControl = (RecordControl) recordPlayer.getControl("RecordControl");
		recordControl.reset();
		if (recordControl != null) {
			baos = new ByteArrayOutputStream();
			recordControl.setRecordStream(baos);
			// recordControl.setRecordLocation(path);
			recordControl.startRecord();
			recordPlayer.start();
		}
	}

	public void recordCommit() throws IOException {
		if (recordControl != null) {
			recordControl.commit();
			baos = AmrToWav.converAudioFiles(baos);
			System.out.println("COMMIT--SIZE = " + baos.size());
		}
	}

	public ByteArrayOutputStream getAudio() {
		return baos;
	}

	public void playAudio() {
		InputStream is = new ByteArrayInputStream(baos.toByteArray());

		try {
			player = Manager.createPlayer(is, "audio/x-wav");
			player.start();
			addAudioPlayerListener();
			// long timeBaseTime = player.getTimeBase().getTime();
			// long startTime = new Date().getTime();
			// long endTime = startTime + timeBaseTime;
			// while(endTime <= new Date().getTime()){
			// player.close();
			// }
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MediaException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void addAudioPlayerListener() {
		player.addPlayerListener(new PlayerListener() {
			public void playerUpdate(Player player, String event,
					Object eventData) {
				if (player.getState() == player.PREFETCHED) {
					player.close();
					fireEvent();
				}
			}
		});
	}

	public void setListener(AudioPlayerListener listener) {
		this.audioPlayerListener = listener;
	}

	private void fireEvent() {
		audioPlayerListener.listener();
	}
}
